home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / TransSkel Pascal 2.5 / TransSkel / TransSkel.p < prev    next >
Encoding:
Text File  |  1995-01-02  |  53.7 KB  |  1,783 lines  |  [TEXT/PJMM]

  1. {    TransSkel version 2.00 - Transportable application skeleton}
  2.  
  3. {    TransSkel is public domain and was originally written in LightSpeed C by:}
  4.  
  5. {            Paul DuBois}
  6. {            Wisconsin Regional Primate Research Center}
  7. {            1220 Capital Court}
  8. {            Madison WI  53706  USA}
  9.  
  10. {    UUCP:    [allegra,ihnp4,seismo]!uwvax!rhesus!dubois }
  11. {    ARPA:    dubois@rhesus.primate.wisc.edu}
  12. {    The Pascal Version of TransSkel is public domain and was ported and changed by        }
  13.  
  14. {            Owen Hartnett            }
  15. {            Ωhm Software            }
  16. {            163 Richard Drive        }
  17. {            Tiverton, RI 02878        }
  18.  
  19. {    CSNET:    omh@cs.brown.edu.CSNET                                             }
  20. {    ARPA:        omh%cs.brown.edu                                                    }
  21. {    UUCP:        [ihnp4,allegra]!brunix !omh                                            }
  22.  
  23. {    This version of TransSkel written for Lightspeed Pascal.  Lightspeed Pascal is a}
  24. {    trademark of:}
  25. {            THINK Technologies, Inc}
  26. {            420 Bedford Street  Suite 350}
  27. {            Lexington, MA  02173  USA}
  28.  
  29. {  History}
  30. {  06/13/86    Beta version. (pd) }
  31. {  08/27/86    Version number changed to 1.01.(pd)}
  32. {              v1.0 DoGrow bug fixed - the port at the point of the}
  33. {              InvalRect could have been anything; the fix is to set}
  34. {              the port to the grown window first.  This also explains}
  35. {              why the kludge to DoActivate in v1.0 worked.(pd)}
  36. {  10/02/86    Version number changed to 1.02, as a result of adding}
  37. {            modifications by David W. Berry (well!dwb@lll-lcc.arpa)}
  38. {            for supporting window zooming.  Also used his modifications}
  39. {            for supporting modeless dialogs (though not in the same}
  40. {            form).  Dialogs can be #define'd on or off.(pd)}
  41.  
  42. {12/ 28 / 86 Version number changed to 1.03 . Modified to work under LightspeedC v . 2.01 }
  43. {            - took out definitions for window zooming stuff , as it is now supported by the compiler}
  44. {             directly . Also declared DoZoom static , fixing an oversight . ( pd )}
  45. { 01 / 18 / 86 Put a SetPort into DoZoom - ZoomWindow requires port to be}
  46. {            set to window being zoomed . ( pd )}
  47. { 02 / 05 / 86 Version number changed to 1.04 . Big change : port setting behavior made explicit}
  48. {             - the only persistant switch occurs when a window comes active . This changes }
  49. {            underlying programming model ( see manual for detailed discussion ) . Thanks to}
  50. {             Duane Williams for pointing out that this should be done . Typedef 'd }
  51. {            integer/long variables to Integer, Longint to facilitate coversion to other C }
  52. {            compilers . More complete type-casting done . LightspeedC does a lot of it }
  53. {            automatically , other compilers may not . ( pd - this version never released ) }
  54. {03 / 02 / 87 Fixed bug whereby clicks in drag region of non - active windows may not bring }
  55. {            window to front . Seems to be due to DragWindow calling StillDown to see    if mouse is still }
  56. {            down .    If the machine was busy    otherwise when click occurred and }
  57. {            mouse already up when DragWindow is called , the click ends up being ignored . }
  58. {            Thanks to Roger Humphrey for finding this one . }
  59.  
  60. {* * * Changes implemented first by omh to Pascal Version}
  61.  
  62. { 12/24/86  Finished first Pascal version.   Dialogs cannot be defined off.     (omh)}
  63.  
  64. {4 / 18 / 87 Changed Desk Accessory code so it 's more tolerant of memory}
  65. {            conditions for desk accessories . ( omh ) }
  66. {7 / 12 / 87 Added "cache " code to GetWDHandler . Now TransSkel figures }
  67. {            that an event is most likely to occur for the same window as the previous }
  68. {            event . Thus the WindowPtr and WDHandle for events are cached and examined }
  69. {            to avoid searching through the handler list . ( omh ) }
  70. {7 / 12 / 87 Excised the notorious "SetPort "excess . As pointed out by Duane Williams ,}
  71. {             SetPort traps abounded unnecessarily in version 1.02 . These have been eliminated }
  72. {            now with two exceptions . First , the port is set when a window handler }
  73. {            is installed . The justification for this is that when a handler is installed , it }
  74. {            is likely that further processing will be done on it immediately . The application gets }
  75. {            control immediately after the handler is installed anyway , so this behavior can be manually }
  76. {            overridden where necessary . Second , when a window is activated , the port is}
  77. {            set to it . This follows the model of keeping the port in sync with the }
  78. {            active window . ( omh ) }
  79. {7 / 14 / 87 Added grow zone function installation    and MoreMasters to SkelInit , }
  80. {            which now requires two parameters . The first indicates the number of times to call }
  81. {            MoreMasters . The second is a ProcPtr indicating a user - supplied grow zone}
  82. {            function to be called when memory problems occur .  If nil , no grow zone}
  83. {            function is    installed . ( omh ) }
  84. {7 / 14 / 87 SkelMenu , SkelWindow , and SkelDialog now return zero or non - zero to indicate }
  85. {            failure or success of handler allocation . This could break * all * previous TransSkel }
  86. {            applications ( as will the change to SkelInit , above . Please see the section "How to }
  87. {            adapt old TransSkel to New "    in the manual    for detailed specifications on }
  88. {            how to convert your old programs . TransSkel becomes more memory conscious}
  89. {            with these changes . The functions SkelMenu , SkelWindow , and }
  90. {            SkelDialog are the only routines which actually allocate memory . Since they may be }
  91. {            called at any time , knowing that you have enough memory becomes important . Thus , }
  92. {            these routines return a value to indicate what happened .  If they return zero ,}
  93. {             then memory allocation failed . ( omh ) }
  94. {10 / 21 / 87 Added another parameter to SkelMenu:  drawBar: Boolean . This tells SkelMenu }
  95. {            whether to draw the menu bar after adding the Menu . This is done to eliminate }
  96. {            the menus popping up one at a time . Simply call SkelMenu  with drawBar false}
  97. {            until the    last time you call SkelMenu , then call it (for the last menu )}
  98. {            with drawBar true . ( omh ) }
  99. {10 / 26 / 87 Removed declarations for zoom - in and zoom - out . Added Pascal }
  100. {            changes ( above ) to C version . ( omh )}
  101.  
  102. {    02 / 02 / 88 Merged pd 's 1.04 changes with those of omh, above, to create}
  103. {            release version 2.0 . Fixed bug whereby cmd - key equivalents}
  104. {            for menu selections would execute twice if DA window in front . Thanks }
  105. {            to Don Fredkin and Julian Vrieslander for finding this one , and to Don for the}
  106. {             best fix . ( pd ) }
  107. { 10/28/88 Removed all New Rom calls. }
  108. { 10/28/88 Added support for conditional compilation for dialogs and MPW support.  By setting }
  109. {            the Think_pascal flag to false, TransSkel will run under MPW. Now correctly written for LSP 2.0}
  110.  
  111. {Some fixes done later by Ingemar Ragnemalm. Search for "Ingemar" fo find these.}
  112. {They include some bug fix and hierarcical menu support (call SkelHMenu instead of SkelMenu}
  113. {for those menus).}
  114.  
  115. {New fix 18/9-93: Added a filter proc for dialogs, to allow special event processing before}
  116. {an event is passed to IsDialogEvent, when a modeless dialog is in the front. This makes it possible}
  117. {to use user items in modeless dialogs, and to handle return/enter.}
  118.  
  119. {Added WNE-support. Use SkelSetSleep and SkelSetMouseRgn if you need them. /Ingemar}
  120.  
  121. {Added FindWindowByRefcon, a routine that is useful for certain multi-window appplications.}
  122.  
  123. {july -94: Plugged in suspend/resume-handlers, conforming with TransSkel 3.0. (Handler should}
  124. {take a boolean as parameter. If the boolean is true, the application was resumed, otherwise it was}
  125. {suspended.) Processes Apple Events by calling AEProcessAppleEvent for you.}
  126.  
  127. unit TransSkel;
  128.  
  129. interface
  130.  
  131. {$SETC supportDialogs:= true }
  132.                     { Set to false to disallow modeless dialog support and save code space }
  133.                 { Set to false to have SkelInit call QuickDraw Inits: InitGraf, InitDialog, etc. }
  134.  
  135. {$IFC UNDEFINED THINK_PASCAL}
  136.  
  137.     uses
  138.         Memtypes, Quickdraw, OSIntf, ToolIntf, PackIntf;
  139. {$ENDC}
  140.  
  141.     procedure SkelInit (noMasters: integer; myGrowZone: ProcPtr);
  142.     procedure SkelMain;
  143.     procedure SkelWhoa;
  144.     procedure SkelClobber;
  145.     function SkelMenu (theMenu: MenuHandle; pSelect: ProcPtr; pClobber: ProcPtr; DrawBar: Boolean): Boolean;
  146.     function SkelHMenu (theMenu: MenuHandle; pSelect: ProcPtr; pClobber: ProcPtr): Boolean; {Added by Ingemar 22/8 -93}
  147.     procedure SkelRmveMenu (theMenu: MenuHandle);
  148.     procedure SkelApple (aboutTitle: Str255; aboutProc: ProcPtr);
  149.     function SkelWindow (theWind: WindowPtr; pMouse, pKey, pUpdate, pActivate, pClose, pClobber, pIdle: ProcPtr; frontOnly: Boolean): Boolean;
  150.     procedure SkelRmveWind (theWind: WindowPtr);
  151. {$IFC supportDialogs }
  152.     function SkelDialog (theDialog: DialogPtr; pEvent, pClose, pClobber, pFilter: ProcPtr): Boolean; {pFilter added by Ingemar 18/9-93}
  153.     procedure SkelRmveDlog (theDialog: DialogPtr);
  154. {$ENDC}
  155.     procedure SkelGrowBounds (theWind: WindowPtr; hLO, vLo, hHi, vHi: integer);
  156.     procedure SkelEventMask (mask: integer);
  157.     procedure SkelGetEventMask (var mask: integer);
  158.     procedure SkelBackground (p: ProcPtr);
  159.     procedure SkelGetBackground (var p: ProcPtr);
  160.     procedure SkelEventHook (p: ProcPtr);
  161.     procedure SkelGetEventHook (var p: ProcPtr);
  162. {$IFC supportDialogs }
  163.     procedure SkelDlogMask (mask: integer);
  164.     procedure SkelGetDlogMask (var mask: integer);
  165. {$ENDC}
  166. {Two new procedures for WNE-support, added by Ingemar 12/11-93}
  167.     procedure SkelSetSleep (newSleep: Longint);
  168.     procedure SkelSetMouseRgn (newMouseRgn: RgnHandle);
  169. {Utility function, added by Ingemar 13/7-94}
  170.     function FindWindowByRefcon (theRefCon: Longint): WindowPtr;
  171. {Suspend/resume, added by Ingemar 23/7 -94}
  172.     procedure SkelSetSuspendResume (p: ProcPtr);
  173.     function SkelGetSuspendResume: ProcPtr;
  174. {Mouse moved events, added by Ingemar jan -95:}
  175.     procedure SkelSetMouseMoved (p: ProcPtr);
  176.     function SkelGetMouseMoved: ProcPtr;
  177.  
  178. implementation
  179.  
  180. {Some stuff that are here to avoid including EPPC and AppleEvents, added by Ingemar 23/7 -94}
  181.     const
  182.         kHighLevelEvent = 23;
  183.     function AEProcessAppleEvent (theEventRecord: EventRecord): OSErr;
  184.     inline
  185.         $303C, $021B, $A816;
  186.  
  187.  
  188.  
  189.     const
  190.         mBarHeight = 20;    { menu bar height.  All window sizing}
  191.  
  192.         growZoneSize = 4000;        {  Size of memory to be freed when GrowZone Proc called }
  193.  
  194.         defaultSleep = 5;        { Added by Ingemar dec -93. SkelInit uses this value for sleep time.}
  195.                             { The programmer can change it with SkelSetSleep }
  196.  
  197. {    This window zooming stuff may need to be removed if you use the new Rom libraries        }
  198. {    if not, then you can add zooming without the overhead of the new Rom libs.  See TrackBox    }
  199. {     routine also.                                                                                            }
  200.  
  201. {    Window and Menu handler types, constants, variables.}
  202.  
  203. {    whList and mhList are the lists of window and menu handlers.}
  204. {    whClobOnRmve and mhClobOnRmve are true if the handler disposal proc}
  205. {    is to be called when a handler is removed.  They are temporarily set}
  206. {    false when handlers are installed for windows or menus that already}
  207. {    have handlers - the old handler is removed WITHOUT calling the}
  208. {    disposal proc.}
  209.  
  210. {    Default lower limits on window sizing of 80 pixels both directions is}
  211. {    sufficient to allow text windows room to draw a grow box and scroll}
  212. {    bars without having the thumb and arrows overlap.  These values may}
  213. {    be changed if such a constraint is undesirable with SkelGrowBounds.}
  214. {    Default upper limits are for the Macintosh, not the Lisa, but are set}
  215. {    per machine in SkelInit.}
  216.  
  217.     type
  218.         WHandlerPtr = ^WHandler;
  219.         WHandlerHnd = ^WHandlerPtr;
  220.         WHandler = record
  221.                 whWind: WindowPtr;    {window/dialog to be handled    }
  222.                 whClobber: ProcPtr;    { data structure disposal proc    }
  223.                 whMouse: ProcPtr;        { mouse-click handler proc        }
  224.                 whKey: ProcPtr;        { key-click handler proc            }
  225.                 whUpdate: ProcPtr;        { update handler proc                }
  226.                 whActivate: ProcPtr;    { activate event handler proc    }
  227.                 whClose: ProcPtr;        { close "event" handler proc        }
  228.                 whIdle: ProcPtr;            { main loop proc                    }
  229. {$IFC supportDialogs }
  230.                 whEvent: ProcPtr;        { dialog event proc                }
  231.                 whFilter: ProcPtr;        { dialog filter proc ADDED BY INGEMAR 18/9 -93}
  232. {$ENDC }
  233.                 whHasGrow: Boolean;    { can window grow?                }
  234.                 whGrow: Rect;            { limits on window sizing        }
  235.                 whSized: Boolean;        { true = window was resized    }
  236.                 whFrontOnly: Boolean;    { true = idle only when active    }
  237.                 whNext: WHandlerHnd;            { next window handler            }
  238.             end;
  239.  
  240.         MHandlerPtr = ^MHandler;
  241.         MHandlerHnd = ^MHandlerPtr;
  242.  
  243.         MHandler = record
  244.                 mhID: integer;                { menu id                                    }
  245.                 mhSelect: ProcPtr;            { item selection handler proc            }
  246.                 mhClobber: ProcPtr;        { menu disposal handler proc            }
  247.                 mhNext: MHandlerHnd;        { next menu handler                        }
  248.             end;
  249.  
  250.     var
  251.         whList: WHandlerHnd;                { list of menu handlers }
  252.         whClobOnRmve: Boolean;
  253.         growRect: Rect;
  254.         mhList: MHandlerHnd;
  255.         mhClobOnRmve: Boolean;
  256.  
  257. {    Variables for default Apple menu handler.  appleID is set to 1 if}
  258. {    SkelApple is called and is the id of the Apple menu, appleAboutProc}
  259. {    is the procedure to execute if there is an About... item and it's}
  260. {    chosen from the Apple menu.  If doAbout is true, then the menu}
  261. {    contains the About... item, otherwise it's just desk accessories.}
  262.  
  263.         appleMenu: MenuHandle;
  264.         appleID: integer;
  265.         appleAboutProc: ProcPtr;
  266.         doAbout: Boolean;
  267.  
  268. {    Miscellaneous}
  269.  
  270. {    screenPort points to the window manager port.}
  271.  
  272. {    doneFlag determines when SkelMain returns.  It is set by calling}
  273. {    SkelWhoa(), which the host does to request a halt.}
  274.  
  275. {    pBkgnd points to a background procedure, to be run during event}
  276. {    processing.  Set it with SkelBackground.  If nil, there's no}
  277. {    procedure.}
  278.  
  279. {    pEvent points to an event-inspecting hook, to be run whenever an}
  280. {    event occurs.  Set it with SkelEventHook.  If nil, there's no}
  281. {    procedure.}
  282.  
  283. {    eventMask controls the event types requested in the GetNextEvent}
  284. {    call in SkelMain.}
  285.  
  286. {    diskInitPt is the location at which the disk initialization dialog}
  287. {    appears, if an uninitialized disk is inserted.}
  288.  
  289.         screenPort: GrafPtr;
  290.         doneFlag: integer;
  291.         pBkgnd: ProcPtr;
  292.         pEvent: ProcPtr;
  293.         eventMask: integer;
  294.         diskInitPt: Point;
  295.  
  296. {Added by Ingemar 12/11-93, for WNE-support:}
  297.         WNEImplemented: Boolean;
  298.         sleepTicks: Longint;
  299.         mouseRgn: rgnHandle;
  300. {…and later, for suspend/resume support:}
  301.         gSuspendResumeHandler: ProcPtr;
  302.         gMouseMovedHandler: ProcPtr;
  303. {For proper handling of suspend/resume:}
  304.         gMultiFinderAware: Boolean;
  305.  
  306. {$IFC supportDialogs }
  307.  
  308. {    Events that are passed to dialogs.  Others are ignored.}
  309. {    Standard mask passes , mousedown, keydown, autokey, update,}
  310. {    activate and null events.  Null events are controlled by bit 0.}
  311.  
  312.         dlogEventMask: integer;
  313. {$ENDC}
  314.         pEventflag: Boolean;
  315.  
  316. {    "caching" global variables.  previous version would search down the window }
  317. {    list for every event it found.  Now, if the event happened to the same window }
  318. {    as last time, GetWDHandler will just do a simple compare }
  319. {    and return the last window handler.  This speeds up multiple window applications }
  320. {    immensely, at only a slight cost when you activate a new window (one }
  321. {    compare!)  If you don't like it, use the old version. }
  322.  
  323.         oldWindow: WindowPtr;
  324.         oldWDHandler: WHandlerHnd;
  325.  
  326. {    Global for built in "Grow Zone" function  }
  327.  
  328.         safetyHandle: Handle;
  329.  
  330.         myDitl: packed array[0..100] of byte;
  331.  
  332. { Rather than including the entire new ROM libraries, with all the other stuff you might not use    }
  333. { I've instead included just the Zoom box stuff here.  Depending on your status, you can either    }
  334. { leave things as they are, and only use zooming from the new Rom libs, or comment out the        }
  335. { calls, and include the new Rom libraries if you want to incorporate other new Rom calls        }
  336.  
  337.  
  338. { -------------------------------------------------------------------- }
  339. {                        Internal (private) Routines                                    }
  340. { -------------------------------------------------------------------- }
  341.  
  342.  
  343.  
  344. {    Get handler associated with user or dialog window.}
  345. {    Return nil if window doesn't belong to any known handler.}
  346. {    This routine is absolutely fundamental to TransSkel.}
  347.  
  348.     function GetWDHandler (theWind: WindowPtr): WHandlerHnd;
  349.  
  350.         var
  351.             h: WHandlerHnd;
  352.     begin
  353.         h := WhList;
  354.         GetWDHandler := nil;
  355.         if theWind = oldWindow then            {  caching code     }
  356.             GetWDHandler := oldWDHandler
  357.         else
  358.             while h <> nil do
  359.                 if h^^.whWind = theWind then
  360.                     begin
  361.                         oldWindow := theWind;            { Load in new values for new window }
  362.                         oldWDHandler := h;
  363.                         GetWDHandler := h;
  364.                         h := nil;
  365.                     end
  366.                 else
  367.                     h := WHandlerHnd(h^^.whNext);
  368.     end;
  369.  
  370. { Get Handler associated with user window.  Return nil if window doesn't}
  371. {  have a Handler. }
  372.  
  373.     function GetWHandler (theWind: WindowPtr): WHandlerHnd;
  374.  
  375.         var
  376.             h: WHandlerHnd;
  377.             myPeek: WindowPeek;
  378.  
  379.     begin
  380. {BUG FIXED by Ingemar 19/9-93. This function retured garbage when passed a dialog}
  381.         h := GetWDHandler(theWind);
  382.         myPeek := WindowPeek(theWind);
  383.         GetWHandler := nil; {default, moved up by Ingemar}
  384.         if h <> nil then
  385.             begin
  386.                 if mypeek^.windowKind <> dialogKind then
  387.                     GetWHandler := h;
  388.             end;
  389.     end;
  390.  
  391. {$IFC supportDialogs }
  392.  
  393. {    Get handler associated with dialog window.}
  394. {    Return nil if window doesn't belong to any known handler.}
  395.  
  396.     function GetDHandler (theDialog: WindowPtr): WHandlerHnd;
  397.  
  398.         var
  399.             h: WHandlerHnd;
  400.             myPeek: WindowPeek;
  401.  
  402.     begin
  403. {BUG FIXED by Ingemar 19/9-93. This function retured garbage when passed a non-dialog}
  404.         h := GetWDHandler(theDialog);
  405.         myPeek := WindowPeek(theDialog);
  406.         GetDHandler := nil; {default - moved up by Ingemar}
  407.         if h <> nil then
  408.             begin
  409.                 if mypeek^.windowKind = dialogKind then
  410.                     GetDHandler := h;
  411.             end;
  412.     end;
  413. {$ENDC}
  414.  
  415. {Two new routines added by Ingemar 12/11-93 for WNE support:}
  416.     procedure SkelSetSleep (newSleep: Longint);
  417.     begin
  418.         sleepTicks := newSleep;
  419.     end;
  420.     procedure SkelSetMouseRgn (newMouseRgn: RgnHandle);
  421.     begin
  422.         mouseRgn := newMouseRgn;
  423.     end;
  424.  
  425. {Utility routine added by Ingemar july 1994. Finds a window in the window list that has the same}
  426. {refCon as the value passed. This is useful for programs where several windows share window handlers.}
  427. {(To be precise, i needed it for a program where I have several connections to other Macs over Appletalk.)}
  428.     function FindWindowByRefcon (theRefCon: Longint): WindowPtr;
  429.         var
  430.             h: WHandlerHnd;
  431.     begin
  432.         FindWindowByRefcon := nil;
  433.         h := WhList;
  434.         while h <> nil do
  435.             if WindowPeek(h^^.whWind)^.refCon = theRefCon then
  436.                 begin
  437.                     FindWindowByRefcon := h^^.whWind;
  438.                     exit(FindWindowByRefcon);
  439.                 end
  440.             else
  441.                 h := WHandlerHnd(h^^.whNext);
  442.     end;
  443.  
  444.     procedure SkelSetSuspendResume (p: ProcPtr);
  445.     begin
  446.         gSuspendResumeHandler := p;
  447.     end;
  448.     function SkelGetSuspendResume: ProcPtr;
  449.     begin
  450.         SkelGetSuspendResume := gSuspendResumeHandler;
  451.     end;
  452.  
  453.     procedure SkelSetMouseMoved (p: ProcPtr);
  454.     begin
  455.         gMouseMovedHandler := p;
  456.     end;
  457.     function SkelGetMouseMoved: ProcPtr;
  458.     begin
  459.         SkelGetMouseMoved := gMouseMovedHandler;
  460.     end;
  461.  
  462.  
  463. {The following procedures are Pascal "glue" that allows Pascal to call a Procedure    }
  464. { from a ProcPtr.  It is similar to (*p) () construct used in the C dialect.  Different    }
  465. { procedures are necessary for the reason of Pascal's strongly typed parameter        }
  466. { list.  Fortunately, there are not too many calls which use different param lists        }
  467.  
  468.     procedure CallPMouse (thePoint: Point; theTime: longint; theMods: integer; myProc: ProcPtr);
  469.  
  470.     inline
  471.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  472.         $4e90;
  473.  
  474.     procedure CallPKey (theChar: char; theMods: integer; myProc: ProcPtr);
  475.  
  476.     inline
  477.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  478.         $4e90;
  479.  
  480.     procedure CallPEvent (theitem: integer; var theEvent: EventRecord; myProc: ProcPtr);
  481.  
  482.     inline
  483.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  484.         $4e90;
  485.  
  486.     function callotherEvent (var theEvent: EventRecord; myProc: ProcPtr): Boolean;
  487.  
  488.     inline
  489.         $205f, $4e90;
  490.  
  491.  
  492.     procedure CallPBoolean (myBool: Boolean; myProc: ProcPtr);
  493.  
  494. { Two calls use Booleans as one parameter arguments.  This procedure handles    }
  495. { both of them.                                                                            }
  496.  
  497.     inline
  498.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  499.         $4e90;
  500.  
  501.     procedure CallPInt (myInt: integer; myProc: ProcPtr);
  502.  
  503. { Two calls use Booleans as one parameter arguments.  This procedure handles    }
  504. { both of them.                                                                            }
  505.  
  506.     inline
  507.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  508.         $4e90;
  509.  
  510.     procedure CallPMenu (myMenu: MenuHandle; myProc: ProcPtr);
  511.  
  512. { Handle removeal of menus.     }
  513.  
  514.     inline
  515.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  516.         $4e90;
  517.  
  518.     procedure CallPnoarg (myProc: ProcPtr);
  519.  
  520. { For all the Procedures that are called with no arguments                            }
  521.  
  522.     inline
  523.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  524.         $4e90;
  525.  
  526.  
  527. {ADDED BY INGEMAR 18/9-93 to support new dialog filters}
  528. {IS IT POSSIBLE to use this for functions?}
  529.     procedure CallPfilter (theDialog: DialogPtr; var theEvent: EventRecord; var result: Boolean; myProc: ProcPtr);
  530.     inline
  531.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  532.         $4e90;
  533.  
  534. {    General menu-handler.  Just passes selection to the handler's}
  535. {    select routine.  If the select routine is nil, selecting items from}
  536. {    the menu is a nop.}
  537.  
  538.     procedure DoMenuCommand (command: longint);
  539.  
  540.         var
  541.             menu: integer;
  542.             item: integer;
  543.             mh: MHandlerHnd;
  544.             p: ProcPtr;
  545.  
  546.     begin
  547.         menu := HiWord(command);
  548.         item := LoWord(command);
  549.         mh := mhList;
  550.         while (mh <> nil) do
  551.             begin
  552.                 p := mh^^.mhSelect;
  553.                 if ((menu = mh^^.mhID) and (p <> nil)) then
  554.                     begin
  555.                         CallPInt(item, p);
  556.                         mh := nil;
  557.                     end
  558.                 else
  559.                     mh := mh^^.mhNext;
  560.             end;
  561.         HiliteMenu(0);
  562.     end;
  563.  
  564. {    Apple menu handler}
  565.  
  566. {    DoAppleItem:  If the first item was chosen, and there's an "About..."}
  567. {    item, call the procedure associated with it (if not nil).  If there}
  568. {    is no "About..." item or the item was not the first one, then open}
  569. {    the associated desk accessory.  The port is saved and restored}
  570. {    because OpenDeskAcc does not always preserve it correctly.}
  571.  
  572. {    DoAppleClobber disposes of the Apple menu.}
  573.  
  574.     procedure DoAppleItem (item: integer);
  575.  
  576.         var
  577.             curPort: GrafPtr;
  578.             str: Str255;
  579.             ignore: integer;
  580.             h: Handle;
  581.  
  582.     begin
  583.         if doAbout and (item = 1) then
  584.             begin
  585.                 if appleAboutProc <> nil then
  586.                     CallPnoarg(appleAboutProc);
  587.             end
  588.         else
  589.             begin
  590.                 GetPort(curPort);
  591.                 GetItem(appleMenu, item, str);
  592.                 SetResLoad(false);
  593.                 h := GetNamedResource('DRVR', str);
  594.                 SetResLoad(true);
  595.                 if h <> nil then
  596.                     begin
  597.                         ResrvMem(SizeResource(h) + $1000);
  598.                         ignore := OpenDeskAcc(str);
  599.                     end;
  600.                 SetPort(curPort);
  601.             end;
  602.     end;
  603.  
  604.     procedure DoAppleClobber;
  605.     begin
  606.         DisposeMenu(appleMenu);
  607.     end;
  608.  
  609. { --------------------------------------------------------------------     }
  610. {                        Window-handler routing routines                            }
  611. {                                                                                        }
  612. {    Each routine sets the port to the handler's window before executing        }
  613. {    the handler procedure.                                                            }
  614. { --------------------------------------------------------------------     }
  615.  
  616.  
  617. {    Pass local mouse coordinates, click time, and the modifiers flag}
  618. {    word to the handler.  Should not be necessary to set the port, as}
  619. {       the click is passed to the active window's hander. }
  620.  
  621.     procedure DoMouse (h: WHandlerHnd; theEvent: EventRecord);
  622.  
  623.         var
  624.             p: ProcPtr;
  625.             thePt: Point;
  626.  
  627.     begin
  628.         if (h <> nil) then
  629.             begin
  630.                 p := h^^.whMouse;
  631.                 if p <> nil then
  632.                     begin
  633.                         thePt := theEvent.where;
  634.                         GlobalToLocal(thePt);
  635.                         CallPMouse(thePt, theEvent.when, theEvent.modifiers, p);
  636.                     end;
  637.             end;
  638.     end;
  639.  
  640. {    Pass the character and the modifiers flag word to the handler.}
  641. {    Should not be necessary to set the port, as the  click is passed to the}
  642. {    active window's handler. }
  643.  
  644.     procedure DoKey (h: WHandlerHnd; ch: char; mods: integer);
  645.         var
  646.             p: ProcPtr;
  647.  
  648.     begin
  649.         if h <> nil then
  650.             begin
  651.                 p := h^^.whKey;
  652.                 if p <> nil then
  653.                     CallPKey(ch, mods, p);
  654.             end;
  655.     end;
  656.  
  657. {    Call the window updating procedure, passing to it an indicator whether the}
  658. {    window has been resized or not.  Then clear the flag, assuming the update}
  659. {    proc took whatever action was necessary to respond to resizing.}
  660. {}
  661. {    If the handler doesn't have any update proc, the Begin/EndUpdate stuff}
  662. {    is still done, to clear the update region.  Otherwise the Window Manager }
  663. {    will keep generating update events for the window, stalling updates of}
  664. {    other windows.    }
  665.  
  666. {    Make sure to save and restore the port, as it's not always the active window}
  667. {    that's updated.    }
  668.  
  669.     procedure DoUpdate (h: WHandlerHnd);
  670.  
  671.         var
  672.             rh: WhandlerHnd;
  673.             p: ProcPtr;
  674.             updPort, tmpPort: GrafPtr;
  675.  
  676.     begin
  677.         rh := h;
  678.         if rh <> nil then
  679.             begin
  680.                 GetPort(tmpPort);
  681.                 updPort := rh^^.whWind;
  682.                 SetPort(updPort);
  683.                 BeginUpdate(updPort);
  684.                 p := rh^^.whUpdate;
  685.                 if p <> nil then
  686.                     begin
  687.                         CallPBoolean(rh^^.whSized, p);
  688.                         rh^^.whSized := false;
  689.                     end;
  690.                 EndUpdate(updPort);
  691.                 SetPort(tmpPort);
  692.             end;
  693.     end;
  694.  
  695. {    Pass activate/deactivate notification to handler.  On activate, set the port to}
  696. {    the window coming active    }
  697.  
  698.     procedure DoActivate (h: WHandlerHnd; active: Boolean);
  699.  
  700.         var
  701.             p: ProcPtr;
  702.             savePort: GrafPtr;
  703.  
  704.     begin
  705.         if h <> nil then
  706.             begin
  707. {Change by Ingemar dec 94: To make multi-window handlers possible/practical, we must be told what window}
  708. {is the current one, preferrably by making that the current port. This is a slight modification of the port-}
  709. {setting model of TS 2.0, but necessary for TransDisplay to work properly.}
  710.                 if not active then
  711.                     GetPort(savePort);
  712. {if active then}
  713.                 SetPort(h^^.whWind);
  714.                 p := h^^.whActivate;
  715.                 if p <> nil then
  716.                     CallPBoolean(active, p);
  717.                 if not active then
  718.                     SetPort(savePort);
  719.             end
  720.     end;
  721.  
  722. {    Execute a window handler's close proc.  The close box for handlers}
  723. {    for temp windows that want to remove themselves when the window}
  724. {    is closed can call SkelRmveWind to dispose of the window}
  725. {    and remove the handler from the window handler list.  Thus, windows}
  726. {    may be dynamically created and destroyed without filling up the}
  727. {    handler list with a bunch of invalid handlers.}
  728.  
  729. {    If the handler doesn't have a close proc, just hide the window.}
  730. {    The host should provide some way of reopening the window (perhaps}
  731. {    a menu selection).  Otherwise the window will be lost from user}
  732. {    control if it is hidden, since it won't receive user-initiated events.}
  733.  
  734. {    Since the close box of only the active window may be clicked, it}
  735. {    is not necessary to set the port . }
  736.  
  737. {    This is called both for regular and dialog windows.}
  738.  
  739.     procedure DoClose (h: WHandlerHnd);
  740.  
  741.         var
  742.             rh: WHandlerHnd;
  743.             p: ProcPtr;
  744.     begin
  745.         rh := h;
  746.         if rh <> nil then
  747.             begin
  748.                 p := rh^^.whClose;
  749.                 if (p <> nil) then
  750.                     CallPnoarg(p)
  751.                 else
  752.                     HideWindow(rh^^.whWind);
  753.             end;
  754.     end;
  755.  
  756. {    Execute a window Handler's clobber proc.  This is called both for regular and dialog windows.}
  757. {    Must save, set and restore port, since any window (not just active one) may be clobbered    }
  758. {    at any time.}
  759. {}
  760. {    Don't need to check whether handler is nil, as in other handler procedures, since this is only}
  761. {    called by SkelRmveWind with a known valid handler.     }
  762.  
  763.     procedure DoClobber (h: WHandlerHnd);
  764.  
  765.         var
  766.             p: ProcPtr;
  767.             curPort: Grafptr;
  768.     begin
  769.         if (h <> nil) then
  770.             begin
  771.                 GetPort(curPort);
  772.                 SetPort(h^^.whWind);
  773.                 p := h^^.whClobber;
  774.                 if p <> nil then
  775.                     CallPnoarg(p);
  776.                 SetPort(curPort);
  777.             end;
  778.     end;
  779.  
  780. {$IFC supportDialogs }
  781.  
  782. {    Handle event if it's for a dialog.  The event must be one of}
  783. {    those that is passed to dialogs according to dlogEventMask.}
  784. {    This mask can be set so that disk-inserts, for instance, don't}
  785. {    get eaten up.}
  786.  
  787.     function DoDialog (theEvent: EventRecord): Boolean;
  788.  
  789.         var
  790.             dh: WHandlerHnd;
  791.             theDialog: DialogPtr;
  792.             myDPeek: DialogPeek;
  793.             what: integer;
  794.             item: integer;
  795.             tmpPort: GrafPtr;
  796.             ignore: Boolean;
  797.             testme: Longint;
  798.             hasfilter, filtered: Boolean;
  799.  
  800.     begin
  801.  
  802. {    handle command keys before they get to IsDialogEvent}
  803.  
  804.         what := theEvent.what;
  805.         testme := BitShift(longint(1), what);
  806.         testme := BitAnd(testme, longint(dlogEventMask));
  807.         if (((what = keydown) or (what = autokey)) and (BitAnd(theEvent.modifiers, cmdkey) <> 0)) then
  808. { Bugfix by Ingemar above! }
  809.             begin
  810.                 DoMenuCommand(MenuKey(Char(BitAnd(theEvent.message, charCodeMask))));
  811.                 DoDialog := true;
  812.             end
  813. {Filter procedure, Added by Ingemar 18/9 -93:}
  814.         else
  815.             begin
  816. {Check if theDialog has whFilter!}
  817. {Bugfix 941026: I used FrontWindow, which was really silly since that won't work}
  818. {for update events!}
  819.  
  820.                 if (what = updateEvt) or (what = activateEvt) then
  821.                     theDialog := DialogPtr(theEvent.message)
  822.                 else
  823.                     theDialog := FrontWindow;
  824.  
  825.                 dh := WHandlerHnd(GetDHandler(theDialog));
  826.                 filtered := false;
  827.                 hasfilter := dh <> nil;
  828.                 if hasfilter then
  829.                     hasfilter := dh^^.whFilter <> nil;
  830.                 if hasfilter then
  831.                     CallPFilter(theDialog, theEvent, filtered, dh^^.whFilter);
  832.                 DoDialog := filtered;
  833.                 if not filtered then
  834. {end of filter proc handling}
  835. {else}
  836.                     if testme > 0 then
  837.                         if IsDialogEvent(theEvent) then
  838.                             begin
  839.                                 if DialogSelect(theEvent, theDialog, item) then
  840.                                     begin
  841.                                         dh := WHandlerHnd(GetDHandler(theDialog));
  842.                                         if (dh <> nil) then
  843.                                             if (dh^^.whEvent <> nil) then
  844.                                                 begin
  845.                                                     GetPort(tmpPort);
  846.                                                     SetPort(theDialog);
  847.                                                     CallPEvent(item, theEvent, dh^^.whEvent);
  848.                                                     SetPort(tmpPort);
  849.                                                 end;
  850.                                     end;
  851.                                 DoDialog := true;
  852.                             end
  853.                         else
  854.                             DoDialog := false;
  855.             end; {to match begin added with filter above}
  856.     end;
  857. {$ENDC}
  858.  
  859. { -------------------------------------------------------------------- }
  860. {                            Event-handling routines                        }
  861. { -------------------------------------------------------------------- }
  862.  
  863. {    Have either sized or zoomed the window.  Invalidate it to force}
  864. {    an update and set the 'resized' flag in the window handler true.}
  865. {    The port is assumed to be set to the port that changed size.        }
  866.  
  867.     procedure TriggerUpdate (h: WHandlerHnd; thePort: GrafPtr);
  868.  
  869.     begin
  870.         InvalRgn(thePort^.visRgn);
  871. {Changed by Ingemar 1/4-94. Was: InvalRect(thePort^.portRect);}
  872. {This is ok for rectangular windows, but all windows aren't rectangular!}
  873.         if (h <> nil) then
  874.             begin
  875.                 h^^.whSized := true;
  876.             end;
  877.     end;
  878.  
  879. {    Size a window.  If the window has a handler, use the grow limits}
  880. {    in the handler record, otherwise use the defaults.}
  881.  
  882. {    The portRect is invalidated to force an update event.    The handler's}
  883. {    update procedure should check the parameter passed to it to check}
  884. {    whether the window has changed size, if it needs to adjust itself to}
  885. {    the new size.  THIS IS A CONVENTION.  Update procs must notice grow}
  886. {    "events", there is no procedure specifically for such events.}
  887.  
  888. {    The clipping rectangle is not reset.  If the host application}
  889. {    keeps the clipping set equal to the portRect or something similar,}
  890. {    then it will have to arrange to treat window growing with more}
  891. {    care.}
  892. {}
  893. {    Since the grow region of only the active window may be clicked, it should}
  894. {    not be necessary to set the port.}
  895.  
  896.     procedure DoGrow (h: WHandlerHnd; thePort: GrafPtr; StartPt: Point);
  897.  
  898.         var
  899.             r: Rect;
  900.             growRes: longint;
  901.  
  902.     begin
  903.         if (h <> nil) then
  904.             begin
  905.                 r := h^^.whGrow;
  906.             end
  907.         else
  908.             r := growRect;
  909.         growRes := GrowWindow(thePort, startPt, r);
  910.         if growRes <> 0 then
  911.             begin
  912.                 SizeWindow(thePort, LoWord(growRes), HiWord(growRes), false);
  913.                 TriggerUpdate(h, thePort);
  914.             end;
  915.     end;
  916.  
  917.  
  918. {    Zoom the current window.  Very similar to DoGrow}
  919. {    Since the zoombox of only the active window may be clicked, it should not be necessary}
  920. {    to set the port.    }
  921.  
  922.     procedure DoZoom (h: WHandlerHnd; thePort: GrafPtr; partcode: integer);
  923.  
  924.     begin
  925.         ZoomWindow(thePort, partcode, false);
  926.         TriggerUpdate(h, thePort);
  927.     end;
  928.  
  929. {    General event handler}
  930.  
  931.     procedure DoEvent (theEvt: EventRecord);
  932.  
  933.         var
  934.             theEvent: EventRecord;
  935.             evtPt: Point;
  936.             evtPort: GrafPtr;
  937.             evtPart: integer;
  938.             evtChar: char;
  939.             evtMods: integer;
  940.             h: WHandlerHnd;
  941.             r: Rect;
  942.             ignore: integer;
  943.  
  944.     begin
  945.         theEvent := theEvt;
  946. {$IFC supportDialogs }
  947.         if not DoDialog(theEvent) then
  948. {$ENDC}
  949.             begin
  950.                 evtPt := theEvent.where;
  951.                 evtMods := theEvent.modifiers; {Bug fixed by Ingemar 941027 - this statement was missing}
  952.                 case theEvent.what of
  953.                     nullEvent: 
  954.                         ;
  955.  
  956. {    Mouse click.  Get the window that the click occurred in, and the}
  957. {    part of the window.    Get WDHandler is called here, not GetWHandler, since}
  958. {    we need the handler for a window which might turn out to be a dialog window,}
  959. {    e.g., if the click is in a close box.}
  960.  
  961.                     mouseDown: 
  962.                         begin
  963.                             evtPart := FindWindow(evtPt, evtPort);
  964.                             h := GetWDHandler(evtPort);
  965.                             case evtPart of
  966.  
  967. {    Click in a desk accessory window.  Pass back to the system.}
  968.  
  969.                                 inSysWindow: 
  970.                                     SystemClick(theEvent, evtPort);
  971.  
  972. {    Click in menu bar.  Track the mouse and execute selected command,}
  973. {    if any.}
  974.  
  975.                                 inMenuBar: 
  976.                                     DoMenuCommand(MenuSelect(evtPt));
  977.  
  978. {    Click in grow box.  Resize window.}
  979.  
  980.                                 inGrow: 
  981.                                     DoGrow(h, evtPort, evtPt);
  982.  
  983. {    Click in title bar.  Drag the window around.  Leave at least}
  984. {    4 pixels visible in both directions.    Bug fix: The window, if not front, is}
  985. {    selected first to make sure it's at least activated (unless the command key is down - see Inside}
  986. {    Macintosh).  DragWindow seems to call StillDown first, so that clicks in drag regions while}
  987. {    machine is busy don't otherwise bring window to front if the mouse is already up by the time}
  988. {    DragWindow is called.}
  989.  
  990.                                 inDrag: 
  991.                                     begin
  992.                                         if (evtPort <> FrontWindow) and (BitAnd(evtmods, cmdKey) = 0) then
  993.                                             SelectWindow(evtPort);
  994.                                         r := screenPort^.portRect;
  995.                                         r.top := r.top + mBarHeight;        { Skip down past menu bar    }
  996.                                         InsetRect(r, 4, 4);
  997.                                         DragWindow(evtPort, evtPt, r);
  998.  
  999. {Added by Ingemar jan -95:}
  1000. {Window has moved. The app can't know this, but it is of interest only for the mouse-moved}
  1001. {event handling – so let's call it!}
  1002.                                         if gMouseMovedHandler <> nil then
  1003.                                             CallPNoArg(gMouseMovedHandler);
  1004.                                     end;
  1005.  
  1006. {    Click in close box.  Call the close proc if the window has one.}
  1007.  
  1008.                                 inGoAway: 
  1009.                                     if (TrackGoAway(evtPort, evtPt)) then
  1010.                                         DoClose(GetWDHandler(evtPort));
  1011.  
  1012. {    Click in content region.  If the window wasn't frontmost (active),}
  1013. {    just select it, otherwise pass the click to the window's mouse}
  1014. {    click handler.}
  1015.  
  1016.                                 inContent: 
  1017.                                     if (evtPort <> FrontWindow) then
  1018.                                         SelectWindow(evtPort)
  1019.                                     else
  1020.                                         DoMouse(h, theEvent);
  1021.  
  1022. {    Click in zoom box.  Track the click and then zoom the window if}
  1023. {    necessary}
  1024.  
  1025.                                 inZoomin, inZoomOut: 
  1026.                                     if (TrackBox(evtPort, evtPt, evtPart)) then
  1027.                                         DoZoom(h, evtport, evtPart);
  1028.                                 otherwise
  1029.                                     ;
  1030.                             end;{mousedown}
  1031.                         end;
  1032.  
  1033. {    Key event.  If the command key was down, process as menu item}
  1034. {    selection, otherwise pass the character and the modifiers flags}
  1035. {    to the active window's key handler.}
  1036.  
  1037. {    If dialogs are supported, there's no check for command-key}
  1038. {    equivalents, since that would have been checked in DoDialog.}
  1039.  
  1040.                     keydown, autokey: 
  1041.                         begin
  1042.                             evtChar := char(BitAnd(theEvent.message, charCodeMask));
  1043.                             evtMods := theEvent.modifiers;
  1044.                             if BitAnd(evtMods, cmdKey) > 0 then
  1045.                                 DoMenuCommand(menuKey(evtChar))
  1046.                             else
  1047.                                 DoKey(GetWHandler(FrontWindow), evtChar, evtMods);
  1048.                         end;
  1049.  
  1050. {    Update a window.}
  1051.  
  1052.                     updateEvt: 
  1053.                         DoUpdate(GetWHandler(WindowPtr(theEvent.message)));
  1054.  
  1055. {    Activate or deactivate a window.}
  1056.  
  1057.                     activateEvt: 
  1058.                         DoActivate(GetWHandler(WindowPtr(theEvent.message)), (BitAnd(theEvent.modifiers, activeFlag) <> 0));
  1059.  
  1060. {    handle inserts of uninitialized disks}
  1061.  
  1062.                     diskEvt: 
  1063.                         if (HiWord(theEvent.message) <> noErr) then
  1064.                             begin
  1065.                                 DILoad;
  1066.                                 ignore := DIBadMount(diskInitPt, theEvent.message);
  1067.                                 DIUnload;
  1068.                             end;
  1069.  
  1070. { Handle suspend/resume and mouse moved events, added by Ingemar 23/7 -94}
  1071.  
  1072.                     osEvt: 
  1073.                         if BAND(BROTL(theEvent.message, 8), $FF) = suspendResumeMessage then
  1074.                             begin
  1075. {Call the suspend/resume procedure, if any}
  1076.                                 if gSuspendResumeHandler <> nil then
  1077.                                     CallPBoolean(BAnd(theEvent.message, 1) <> 0, gSuspendResumeHandler);
  1078. {Added by Ingemar jan -95:}
  1079. {If we are MultiFinder aware, according to our SIZE -1, do activate or deactivate for the front window.}
  1080.                                 if gMultiFinderAware then
  1081.                                     DoActivate(GetWHandler(FrontWindow), BAnd(theEvent.message, 1) <> 0);
  1082.                             end
  1083.                         else if BAND(BROTL(theEvent.message, 8), $FF) = mouseMovedMessage then
  1084. {Added by Ingemar jan -95:}
  1085. {Mouse-moved event}
  1086.                             if gMouseMovedHandler <> nil then
  1087.                                 CallPNoArg(gMouseMovedHandler);
  1088.  
  1089. { Handle Apple Events, added by Ingemar 23/7 -94}
  1090.  
  1091.                     kHighLevelEvent: 
  1092.                         if AEProcessAppleEvent(theEvent) <> noErr then
  1093.                             ;
  1094.  
  1095.                     otherwise
  1096.                 end;
  1097.             end;
  1098.     end;
  1099.  
  1100. { -------------------------------------------------------------------- }
  1101. {                        Interface (public) Routines                        }
  1102. { -------------------------------------------------------------------- }
  1103.  
  1104.  
  1105. {    Initialize the various Macintosh Managers.}
  1106. {    Set default upper limits on window sizing.}
  1107. {    FlushEvents does NOT toss disk insert events, so that disks}
  1108. {    inserted while the application is starting up don't result}
  1109. {    in dead drives.}
  1110. {    NoMasters is the number of times to call MoreMasters.  gzProc is the address of a user - provided}
  1111. {    grow zone function procedure to call if memory gets tight.  Pass nil if none to be used.    }
  1112.  
  1113.     procedure SkelInit;
  1114.         var
  1115.             i: integer;
  1116.  
  1117.         function CheckIfMultiFinderAware: Boolean;
  1118.             type
  1119. {The "SIZE" resource format:}
  1120.                 SizeResRecord = record
  1121.                         multiFinderFlags: Integer;
  1122.                         preferredSize, minimumSize: Longint;
  1123.                     end;
  1124.                 SizeResPtr = ^SizeResRecord;
  1125.                 SizeResHandle = ^SizeResPtr;
  1126.             var
  1127.                 mySize: SizeResHandle;
  1128.                 wasLoaded: Boolean;
  1129.         begin
  1130.             SetResLoad(false);
  1131.             mySize := SizeResHandle(Get1Resource('SIZE', -1));
  1132.             SetResLoad(true);
  1133.             if mySize = nil then
  1134.                 CheckIfMultiFinderAware := false
  1135.             else
  1136.                 begin
  1137.                     wasLoaded := mySize^ <> nil;
  1138.                     if not wasLoaded then
  1139.                         LoadResource(Handle(mySize));
  1140.  
  1141.                     CheckIfMultiFinderAware := BitAnd(mySize^^.multiFinderFlags, $800) <> 0;
  1142.  
  1143.                     if not wasLoaded then
  1144.                         ReleaseResource(Handle(mySize));
  1145.                 end;
  1146.         end;
  1147.  
  1148.     begin {SkelInit}
  1149.  
  1150. { For non-Lightspeed Pascal users, the following inits are included as a compile time option, }
  1151. {  See the $SETC definition at the beginning of the unit.  }
  1152.  
  1153. {$IFC UNDEFINED THINK_PASCAL }
  1154.         InitGraf(@qd.thePort);
  1155.         InitFonts;
  1156.         InitWindows;
  1157.         InitMenus;
  1158.         TEInit;
  1159.         InitDialogs(nil);
  1160.         MaxApplZone;
  1161. {$ENDC}
  1162.  
  1163.         FlushEvents(everyEvent - diskMask, 0);
  1164.         for i := 1 to noMasters do
  1165.             MoreMasters;
  1166.         if myGrowZone <> nil then
  1167.             SetGrowZone(myGrowZone);
  1168.  
  1169.         InitCursor;
  1170.  
  1171. {Added by Ingemar 12/11-93, for WNE-support:}
  1172.         WNEImplemented := NGetTrapAddress($60, ToolTrap) <> NgetTrapAddress($9F, ToolTrap);
  1173.         SkelSetSleep(defaultSleep);
  1174.         SkelSetMouseRgn(nil);
  1175. {End WNE-support}
  1176.  
  1177.         gMultiFinderAware := CheckIfMultiFinderAware;
  1178.  
  1179.         whList := nil;
  1180.         whClobOnRmve := true;
  1181.         SetRect(growRect, 80, 80, 512, 342 - mBarHeight);
  1182.         mhList := nil;
  1183.         mhClobOnRmve := true;
  1184.         appleID := 0;
  1185.         appleAboutProc := nil;
  1186.         doAbout := false;
  1187.         doneflag := 0;
  1188.         pBkgnd := nil;
  1189.         pEvent := nil;
  1190.         pEventflag := false;
  1191.         eventmask := everyEvent;
  1192.         diskInitPt.v := 120;
  1193.         diskInitPt.h := 100;
  1194. {$IFC supportDialogs }
  1195.         dlogEventMask := $16f;
  1196. {$ENDC}
  1197.  
  1198. {    Set upper limits of window sizing to machine screen size.  Allow}
  1199. {    for the menu bar.}
  1200.  
  1201.         GetWMgrPort(screenport);
  1202.         growRect.right := screenPort^.portRect.right;
  1203.         growRect.bottom := screenPort^.portRect.bottom - mBarHeight;
  1204.  
  1205. {    Set caching global variables to nil }
  1206.  
  1207.         oldWindow := nil;
  1208.         oldWDHandler := nil;
  1209.     end; {SkelInit}
  1210.  
  1211. {    Main loop.}
  1212.  
  1213. {    Task care of DA's with SystemTask.}
  1214. {    Run background task if there is one.}
  1215. {    If there is an event, check for an event hook.  If there isn't}
  1216. {    one defined, or if there is but it returns false, call the}
  1217. {    general event handler.  (Hook returns true if TransSkel should}
  1218. {    ignore the event.)}
  1219. {    If no event, call the "no-event" handler for the front window and for}
  1220. {    any other windows with idle procedures that are always supposed}
  1221. {    to run.  This is done in such a way that it is safe for idle procs}
  1222. {    to remove the handler for their own window if they want (unlikely,}
  1223. {    but...)  This loop doesn't check whether the window is really}
  1224. {    a dialog window or not, but it doesn't have to, because such}
  1225. {    things always have a nil idle proc.}
  1226. {    }
  1227. {    doneFlag is reset upon exit.  This allows it to be called}
  1228. {    repeatedly, or recursively.}
  1229.  
  1230. {    Null events are looked at (in SkelMain)}
  1231. {    and passed to the event handler.  This is necessary to make sure}
  1232. {    DialogSelect gets called repeatedly, or the caret won't blink if}
  1233. {    a dialog has any editText items.  Null events are not passed to any event-inspecting hook that may}
  1234. {    be installed.}
  1235.  
  1236.     procedure SkelMain;
  1237.  
  1238.         var
  1239.             theEvent: EventRecord;
  1240.             wh, wh2: WHandlerHnd;
  1241.             w: WindowPtr;
  1242.             haveEvent, testpevent, testbool: Boolean;
  1243.             tmpPort: GrafPtr;
  1244.             p: ProcPtr;
  1245.  
  1246.     begin
  1247.         while doneFlag = 0 do
  1248.             begin
  1249.                 if WNEImplemented then {Added by Ingemar 12/11-93, for WNE-support:}
  1250.                     begin
  1251.                         if pBkgnd <> nil then
  1252.                             CallPnoarg(pBkgnd);
  1253.                         haveEvent := WaitNextEvent(eventMask, theEvent, sleepTicks, mouseRgn);
  1254.                     end
  1255.                 else
  1256.                     begin {Old way:}
  1257.                         SystemTask;
  1258.                         if pBkgnd <> nil then
  1259.                             CallPnoarg(pBkgnd);
  1260.                         haveEvent := GetNextEvent(eventMask, theEvent);
  1261.                     end;
  1262.  
  1263.                 if pEvent <> nil then
  1264.                     testpevent := CallotherEvent(theEvent, pEvent)
  1265.                 else
  1266.                     testpevent := false;
  1267. { following line fixed from version 1.02 & 1.03     [but was still buggy! /Ingemar]}
  1268. {$IFC supportDialogs }
  1269.                 if not testpevent then {haveEvent and <- This is wrong for modeless dialogs according to page 416? Changed by Ingemar 6/8 -93}
  1270. {$ELSEC}
  1271.                     if haveEvent and ((pEvent = nil) or (testpevent = false)) then { Old line. IFC'ad by Ingemar 6/8 -93}
  1272. {$ENDC}
  1273.                         DoEvent(theEvent);
  1274.                 if not haveEvent then
  1275.                     begin
  1276.                         wh := whList;
  1277.                         GetPort(tmpPort);
  1278.                         while wh <> nil do
  1279.                             begin
  1280.                                 wh2 := wh^^.whNext;
  1281.                                 w := wh^^.whWind;
  1282.                                 if ((w = FrontWindow) or not wh^^.whFrontOnly) then
  1283.                                     begin
  1284.                                         SystemTask;
  1285.                                         if (wh^^.whIdle <> nil) then
  1286.                                             begin
  1287.                                                 SetPort(wh^^.whWind);
  1288.                                                 p := wh^^.whIdle;
  1289.                                                 if (p <> nil) then
  1290.                                                     CallPnoarg(p);
  1291.                                             end;
  1292.                                     end;
  1293.                                 wh := wh2;
  1294.                             end;
  1295.                         SetPort(tmpPort);
  1296.                     end;
  1297.             end;
  1298.         doneFlag := 0;
  1299.     end;
  1300.  
  1301. {    Tell SkelMain to stop}
  1302.  
  1303.     procedure SkelWhoa;
  1304.     begin
  1305.         doneFlag := 1;
  1306.     end;
  1307.  
  1308. {    Clobber all the menu, window and dialog handlers}
  1309.  
  1310.     procedure SkelClobber;
  1311.  
  1312.  
  1313.     begin
  1314.         oldWDHandler := nil;
  1315.         oldWindow := nil;
  1316.         while (whList <> nil) do
  1317.             begin
  1318.                 SkelRmveWind(whList^^.whWind);
  1319.             end;
  1320.         while (mhList <> nil) do
  1321.             begin
  1322.                 SkelRmveMenu(GetMHandle(mhList^^.mhID));
  1323.             end;
  1324.     end;
  1325.  
  1326. { -------------------------------------------------------------------- }
  1327. {                        Menu-handler interface routines                            }
  1328. { -------------------------------------------------------------------- }
  1329.  
  1330.  
  1331.  
  1332.  
  1333. {    Install handler for a menu.  Remove any previous handler for it.}
  1334. {    Pass the following parameters:}
  1335.  
  1336. {    theMenu    Handle to the menu to be handled.  Must be created by host.}
  1337. {    pSelect    Proc that handles selection of items from menu.  If this is}
  1338. {            nil, the menu is installed, but nothing happens when items}
  1339. {            are selected from it.}
  1340. {    pClobber Proc for disposal of handler's data structures.  Usually}
  1341. {            nil for menus that remain in menu bar until program}
  1342. {            termination.}
  1343.  
  1344. {    The menu is installed and drawn in the menu bar.}
  1345.  
  1346. {     Return false if no handler could be allocated, true if successful. }
  1347.  
  1348.     function CommonSkelMenu (theMenu: MenuHandle; pSelect: ProcPtr; pClobber: ProcPtr): Boolean;
  1349.         var
  1350.             mh: MHandlerHnd;
  1351.             myHand: Handle;
  1352.     begin
  1353.         mhClobOnRmve := false;
  1354.         SkelRmveMenu(theMenu);
  1355.         mhClobOnRmve := true;
  1356.         myHand := NewHandle(Sizeof(MHandler));
  1357.         CommonSkelMenu := false;
  1358.         if myHand <> nil then
  1359.             begin
  1360.                 CommonSkelMenu := true;                    { show we really got the memory }
  1361.                 mh := MHandlerHnd(myHand);
  1362.                 mh^^.mhNext := mhList;
  1363.                 mhList := MHandlerHnd(myHand);
  1364.                 mh^^.mhID := theMenu^^.menuID;    { get menu id number }
  1365.                 mh^^.mhSelect := pSelect;            { install selection handler }
  1366.                 mh^^.mhClobber := pClobber;        { install disposal handler }
  1367.             end;
  1368.     end;
  1369.  
  1370. {  Install handler for a normal menu }
  1371.  
  1372.     function SkelMenu;
  1373.         var
  1374.             success: Boolean;
  1375.     begin
  1376.         success := CommonSkelMenu(theMenu, pSelect, pClobber);
  1377.         SkelMenu := success;
  1378.         if success then
  1379.             begin
  1380.                 InsertMenu(theMenu, 0);            { put menu at end of menu bar }
  1381.                 if DrawBar then
  1382.                     DrawMenuBar;
  1383.             end;
  1384.     end;
  1385.  
  1386. {    Install handler for a hiearcical menu.  Almost same as above.}
  1387. {    Added by Ingemar 22/8 -93}
  1388.  
  1389.     function SkelHMenu;
  1390.         var
  1391.             success: Boolean;
  1392.     begin
  1393.         success := CommonSkelMenu(theMenu, pSelect, pClobber);
  1394.         SkelHMenu := success;
  1395.         if success then
  1396.             begin
  1397.                 InsertMenu(theMenu, -1);            { put menu at end of menu bar }
  1398.             end;
  1399.     end;
  1400.  
  1401.  
  1402. {    Remove a menu handler.  This calls the handler's disposal routine}
  1403. {    and then takes the handler out of the handler list and disposes}
  1404. {    of it.}
  1405.  
  1406. {    Note that the menu MUST be deleted from the menu bar before calling}
  1407. {    the clobber proc, because the menu bar will end up filled with}
  1408. {    garbage if the menu was allocated with NewMenu (see discussion of}
  1409. {    DisposeMenu in Menu Manager section of Inside Macintosh).}
  1410.  
  1411.     procedure SkelRmveMenu;
  1412.  
  1413.         var
  1414.             mID: integer;
  1415.             h, h2: MHandlerHnd;
  1416.             p: ProcPtr;
  1417.             returnflag: Boolean;
  1418.  
  1419.     begin
  1420.         mID := theMenu^^.menuID;
  1421.         returnflag := false;
  1422.         if mhlist <> nil then
  1423.             begin
  1424.                 if mhList^^.mhID = mID then
  1425.                     begin
  1426.                         h2 := mhlist;
  1427.                         mhList := h2^^.mhNext;
  1428.                     end
  1429.                 else
  1430.                     begin
  1431.                         h := mhList;
  1432.                         while (h <> nil) and not returnflag do
  1433.                             begin
  1434.                                 h2 := h^^.mhNext;
  1435.                                 if (h2 = nil) then
  1436.                                     begin
  1437.                                         h := nil;
  1438.                                         returnflag := true;
  1439.                                     end
  1440.                                 else if h2^^.mhID = mID then
  1441.                                     begin
  1442.                                         h^^.mhNext := h2^^.mhNext;
  1443.                                         h := nil;
  1444.                                     end;
  1445.                                 if h <> nil then
  1446.                                     h := h2;
  1447.                             end;
  1448.                     end;
  1449.                 if not returnflag then
  1450.                     begin
  1451.                         DeleteMenu(mID);
  1452.                         DrawMenuBar;
  1453.                         p := h2^^.mhClobber;
  1454.                         if mhClobOnRmve and (p <> nil) then
  1455.                             CallPMenu(theMenu, p);
  1456.                         DisposHandle(Handle(h2));
  1457.                     end;
  1458.             end;
  1459.     end;
  1460.  
  1461. {    Install a handler for the Apple menu.}
  1462.  
  1463. {    SkelApple is called if TransSkel is supposed to handle the apple}
  1464. {    menu itself.  The title is the title of the first item.  If nil,}
  1465. {    then only desk accessories are put into the menu.  If not nil, then}
  1466. {    the title is entered as the first item, followed by a gray line,}
  1467. {    then the desk accessories.}
  1468.  
  1469. {     SkelApple does not cause the menubar to be drawn, so if the Apple menu is the only menu, }
  1470. {    DrawMenuBar must be called afterward.}
  1471.  
  1472. {    No value is returned, unlike SkelMenu.  It is assumed that SkelApple will be called so early in the}
  1473. {    application that the call to SkelMenu is virtually certain to succeed.  }
  1474.  
  1475.     procedure SkelApple;
  1476.  
  1477.         var
  1478.             appleTitle: Str255;
  1479.             dummy: boolean;
  1480.     begin
  1481.         appleTitle := ' ';
  1482.         appleTitle[1] := char($14);
  1483.         appleID := 1;
  1484.         AppleMenu := NewMenu(appleID, appleTitle);
  1485.         if aboutTitle <> '' then
  1486.             begin
  1487.                 doAbout := true;
  1488.                 AppendMenu(appleMenu, aboutTitle);
  1489.                 AppendMenu(appleMenu, '(-');
  1490.                 AppleAboutProc := aboutProc;
  1491.             end;
  1492.         AddResMenu(appleMenu, 'DRVR');
  1493.         dummy := SkelMenu(appleMenu, @DoAppleItem, @DoAppleClobber, false);
  1494.     end;
  1495.  
  1496. { -------------------------------------------------------------------- }
  1497. {                    Window-handler interface routines                    }
  1498. { -------------------------------------------------------------------- }
  1499.  
  1500.  
  1501.  
  1502. {    Install handler for a window.  Remove any previous handler for it.}
  1503. {    Pass the following parameters:}
  1504.  
  1505. {    theWind    Pointer to the window to be handled.  Must be created by host.}
  1506. {    pMouse    Proc to handle mouse clicks in window.  The proc will be}
  1507. {            passed the point (in local coordinates), the time of the}
  1508. {            click, and the modifier flags word.}
  1509. {    pKey    Proc to handle key clicks in window.  The proc will be passed}
  1510. {            the character and the modifier flags word.}
  1511. {    pUpdate    Proc for updating window.  TransSkel brackets calls to update}
  1512. {            procs with calls to BeginUpdate and EndUpdate, so the visRgn}
  1513. {            is set up correctly.  A flag is passed indicating whether the}
  1514. {            window was resized or not.  BY CONVENTION, the entire portRect}
  1515. {            is invalidated when the window is resized.  That way, the}
  1516. {            handler's update proc can redraw the entire content region}
  1517. {            without interference from BeginUpdate/EndUpdate.  The flag}
  1518. {            is set to false after the update proc is called; the}
  1519. {            assumption is made that it will notice the resizing and}
  1520. {            respond appropriately.}
  1521. {    pActivate Proc to execute when window is activated or deactivated.}
  1522. {            A boolean is passed to it which is true if the window is}
  1523. {            coming active, false if it's going inactive.}
  1524. {    pClose    Proc to execute when mouse clicked in close box.  Useful}
  1525. {            mainly to temp window handlers that want to know when to}
  1526. {            self-destruct (with SkelRmveWind).}
  1527. {    pClobber Proc for disposal of handler's data structures}
  1528. {    pIdle    Proc to execute when no events are pending.}
  1529. {    frontOnly True if pIdle should execute on no events only when}
  1530. {            theWind is frontmost, false if executes all the time.  Note}
  1531. {            that if it always goes, everything else may be slowed down!}
  1532.  
  1533. {    If a particular procedure is not needed (e.g., key events are}
  1534. {    not processed by a handler), pass nil in place of the appropriate}
  1535. {    procedure address.}
  1536.  
  1537. {    Return false  if no handler could be allocated, true if successful.}
  1538.  
  1539.     function SkelWindow;
  1540.  
  1541.         var
  1542.             hHand: WhandlerHnd;
  1543.  
  1544.     begin
  1545.         whClobOnRmve := false;
  1546.         SkelRmveWind(theWind);
  1547.         whClobOnRmve := true;
  1548.  
  1549. {    Get new handler, attach to list of handlers.  It is attached to the beginning of the list, which is simpler;}
  1550. {    the order should be irrelevant to the hose, anyway. }
  1551.  
  1552.         hHand := WHandlerHnd(NewHandle(Sizeof(WHandler)));
  1553.         SkelWindow := false;
  1554.         if hHand <> nil then
  1555.             begin
  1556.                 hHand^^.whNext := whList;
  1557.                 whList := hHand;
  1558.                 with hHand^^ do
  1559.                     begin
  1560.                         SkelWindow := true;                    { Show that we got the memory }
  1561.                         whWind := theWind;
  1562.                         whMouse := pMouse;
  1563.                         whKey := pKey;
  1564.                         whUpdate := pUpdate;
  1565.                         whActivate := pActivate;
  1566.                         whClose := pClose;
  1567.                         whClobber := pClobber;
  1568.                         whIdle := pIdle;
  1569.                         whFrontOnly := frontOnly;
  1570.                         whSized := false;
  1571.                         whGrow := GrowRect;
  1572.                     end;
  1573.             end;
  1574.         SetPort(theWind); {Is this allowed for hidden windows? I thought so, but… /Ingemar, dec 93}
  1575.     end;
  1576.  
  1577. {    Remove a window handler.  This calls the handler's disposal routine}
  1578. {    and then takes the handler out of the handler list and disposes}
  1579. {    of it.}
  1580.  
  1581. {    SkelRmveWind is also called by SkelRmveDlog.}
  1582.  
  1583. {    Note that if the window cache variable is set to the window whose handler is being clobbered, the }
  1584. {    variable must be zeroed.    }
  1585.  
  1586.     procedure SkelRmveWind;
  1587.  
  1588.         var
  1589.             h, h2: WHandlerHnd;
  1590.             returnflag: Boolean;
  1591.  
  1592.     begin
  1593.         if theWind = oldWindow then
  1594.             begin
  1595.                 oldWindow := nil;
  1596. {•    oldWDHandler := nil;•}
  1597.             end;
  1598.  
  1599.         if (whList <> nil) then
  1600.             begin
  1601.                 returnflag := false;
  1602.                 if whList^^.whWind = theWind then
  1603.                     begin
  1604.                         h2 := whlist;
  1605.                         whList := whList^^.whNext;
  1606.                     end
  1607.                 else
  1608.                     begin
  1609.                         h := whList;
  1610.                         while (h <> nil) and not returnflag do
  1611.                             begin
  1612.                                 h2 := h^^.whNext;
  1613.                                 if (h2 = nil) then
  1614.                                     begin
  1615.                                         h := nil;
  1616.                                         returnflag := true;
  1617.                                     end
  1618.                                 else if h2^^.whWind = theWind then
  1619.                                     begin
  1620.                                         h^^.whNext := h2^^.whNext;
  1621.                                         h := nil;
  1622.                                     end;
  1623.                                 if h <> nil then
  1624.                                     h := h2;
  1625.                             end;
  1626.                     end;
  1627.                 if not returnflag then
  1628.                     begin
  1629.                         if (whClobOnRmve) then
  1630.                             DoClobber(h2);
  1631.                         DisposHandle(Handle(h2));
  1632.                     end;
  1633.             end;
  1634.     end;
  1635.  
  1636. {$IFC supportDialogs }
  1637.  
  1638. { -------------------------------------------------------------------- }
  1639. {                    Dialog-handler interface routines                                }
  1640. { -------------------------------------------------------------------- }
  1641.  
  1642.  
  1643.  
  1644. {    Install a dialog handler.  Remove any previous handler for it.}
  1645. {    SkelDialog calls SkelWindow as a subsidiary to install a window}
  1646. {    handler, then sets the event procedure on return.}
  1647.  
  1648. {    Pass the following parameters:}
  1649.  
  1650. {    theDialog    Pointer to the dialog to be handled.  Must be created}
  1651. {            by host.}
  1652. {    pEvent    Event-handling proc for dialog events.}
  1653. {    pClose    Proc to execute when mouse clicked in close box.  Useful}
  1654. {            mainly to dialog handlers that want to know when to}
  1655. {            self-destruct (with SkelRmveDlog).}
  1656. {    pClobber Proc for disposal of handler's data structures}
  1657.  
  1658. {    If a particular procedure is not needed, pass nil in place of}
  1659. {    the appropriate procedure address.}
  1660.  
  1661. {    Return false if no handler could be allocated, true if successful.}
  1662.  
  1663.     function SkelDialog;
  1664.  
  1665.         var
  1666.             wh: WHandlerHnd;
  1667.             aBool: Boolean;
  1668.  
  1669.     begin
  1670.         aBool := SkelWindow(theDialog, nil, nil, nil, nil, pClose, pClobber, nil, false);
  1671.         if aBool <> false then
  1672.             begin
  1673.                 wh := GetWDHandler(theDialog);
  1674.                 wh^^.whEvent := pEvent;
  1675. {Added by Ingemar 18/9 -93:}
  1676.                 wh^^.whFilter := pFilter; {Install a filter function to be called *before* IsDialogEvent!}
  1677.             end;
  1678.         SkelDialog := aBool;
  1679.     end;
  1680.  
  1681. {    Remove a dialog and its handler}
  1682.  
  1683.     procedure SkelRmveDlog;
  1684.  
  1685.     begin
  1686.         SkelRmveWind(theDialog);
  1687.     end;
  1688. {$ENDC}
  1689. { -------------------------------------------------------------------- }
  1690. {                    Miscellaneous interface routines                    }
  1691. { -------------------------------------------------------------------- }
  1692.  
  1693.  
  1694. {    Override the default sizing limits for a window, or, if theWind}
  1695. {    is nil, reset the default limits used by SkelWindow.}
  1696.  
  1697.     procedure SkelGrowBounds;
  1698.  
  1699.         var
  1700.             h: WHandlerHnd;
  1701.             r: Rect;
  1702.  
  1703.     begin
  1704.         if theWind = nil then
  1705.             SetRect(growRect, hLo, vLo, hHi, vHi)
  1706.         else
  1707.             begin
  1708.                 h := GetWHandler(theWind);
  1709.                 if h <> nil then
  1710.                     begin
  1711.                         SetRect(r, hLo, vLo, hHi, vHi);
  1712.                         h^^.whGrow := r;
  1713.                     end;
  1714.             end;
  1715.     end;
  1716.  
  1717. {    Set the event mask.}
  1718.  
  1719.     procedure SkelEventMask;
  1720.  
  1721.     begin
  1722.         eventMask := mask;
  1723.     end;
  1724.  
  1725. {    Return the event mask.}
  1726.  
  1727.     procedure SkelGetEventMask;
  1728.  
  1729.     begin
  1730.         mask := eventMask;
  1731.     end;
  1732.  
  1733. {    Install a background task.  If p is nil, the current task is}
  1734. {    disabled.}
  1735.  
  1736.     procedure SkelBackground;
  1737.  
  1738.     begin
  1739.         pBkgnd := p;
  1740.     end;
  1741.  
  1742. {    Return the current background task.  Return nil if none.}
  1743.  
  1744.     procedure SkelGetBackground;
  1745.     begin
  1746.         p := pBkgnd;
  1747.     end;
  1748.  
  1749. {    Install an event-inspecting hook.  If p is nil, the hook is}
  1750. {    disabled.}
  1751.  
  1752.     procedure SkelEventHook;
  1753.  
  1754.     begin
  1755.         pEvent := p;
  1756.     end;
  1757.  
  1758.     procedure SkelGetEventHook;
  1759.  
  1760.     begin
  1761.         p := pEvent;
  1762.     end;
  1763. {$IFC supportDialogs }
  1764.  
  1765. {    Set the mask for event types that will be passed to dialogs.}
  1766. {    Bit 1 is always set, so that null events will be passed.}
  1767. {    If this is not done, the caret does not blink in editText items.}
  1768.  
  1769.     procedure SkelDlogMask;
  1770.  
  1771.     begin
  1772.         dlogEventMask := BitOr(mask, 1);
  1773.     end;
  1774.  
  1775. {    Return the current dialog event mask.}
  1776.  
  1777.     procedure SkelGetDlogMask;
  1778.  
  1779.     begin
  1780.         mask := dlogEventMask;
  1781.     end;
  1782. {$ENDC}
  1783. end.